home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************
- #
- # displays.c
- #
- # This segment handles the Display Manager notification and
- # repositions application windows in response.
- #
- # Author(s): Michael Marinkovich
- # Eric3 anderson
- # marink@apple.com
- # eric3@apple.com
- #
- # Modification History:
- #
- # 7/21/99 ewa Updated to CW Pro 4. Added sample for use of
- # DMRegisterExtendedNotifyProc to match the use
- # of the AppleEvent notification mechanism.
- # 1/19/99 ewa No longer use nil as the "actualSize" param for
- # AEGetKeyPtr. The AE Mgr uses actualSize and
- # writes to its location (zero if actualSize==nil).
- # 1/19/99 ewa update to CWPro3 and universal interfaces
- # 10/05/96 MWM Removed the fixed window title bar height and
- # replaced it with a func that calculates the
- # proper height.
- # 10/12/95 MWM Initial coding
- #
- #
- # Copyright © 1992-1999 Apple Computer, Inc., All Rights Reserved
- #
- #
- # You may incorporate this sample code into your applications without
- # restriction, though the sample code has been provided "AS IS" and the
- # responsibility for its operation is 100% yours. However, what you are
- # not permitted to do is to redistribute the source as "DSC Sample Code"
- # after having made changes. If you're going to re-distribute the source,
- # we require that you make it clear in the source that the code was
- # descended from Apple Sample Code, but that you've made changes.
- #
- *************************************************************************************/
-
- #include <Events.h>
- #include <ToolUtils.h>
- #include <Gestalt.h>
- #include <OSUtils.h>
- #include <Displays.h>
-
-
- #include "App.h"
- #include "Proto.h"
-
- // Set to 1 to install DM extended notifications
- // Set to 0 to install AppleEvent notifications
- #define USE_DMEXTENDED_NOTIFY 0
-
-
- //----------------------------------------------------------------------
- //
- // Decide at compile time to use AppleEvents or DM extended notifications
- //
- //----------------------------------------------------------------------
-
- OSErr InstallDMNotification(void)
- {
- OSErr err = noErr;
-
- #if USE_DMEXTENDED_NOTIFY
- err = InstallExtendedDMNotification(); // install DM extended Display Notification
- #else
- err = InstallAEDMNotification(); // install AppleEvent Display Notification
- #endif
-
- return err;
-
- }
-
- //----------------------------------------------------------------------
- //
- // InstallAEDMNotification - tell DM that we want to be notified by AE.
- //
- //----------------------------------------------------------------------
-
- OSErr InstallAEDMNotification(void)
- {
- OSErr err = noErr;
-
- err = AEInstallEventHandler(kCoreEventClass, kAESystemConfigNotice,
- NewAEEventHandlerProc(WorldChangedAppleEventProc),
- 0L, false);
- return err;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // WorldChangedAppleEventProc - Display Manager calls this proc when a depth or
- // mode change is made. Your application should
- // handle window repositioning here.
- //
- //----------------------------------------------------------------------
-
- pascal OSErr WorldChangedAppleEventProc(AppleEvent event, AppleEvent reply, long refCon)
- {
- OSErr err = noErr;
-
- err = HandleNotification(&event);
-
- return noErr;
-
- }
-
- //----------------------------------------------------------------------
- //
- // InstallExtendedDMNotification - tell DM that we want to be have an
- // extended notification. Note that we
- // leak the UPP. We should remember it
- // and toss it when we no longer need
- // it.
- //
- //----------------------------------------------------------------------
-
- OSErr InstallExtendedDMNotification(void)
- {
- OSErr err = noErr;
- DMExtendedNotificationUPP panelNotificationUPP = nil;
- ProcessSerialNumber currentPSN;
-
- (void)GetCurrentProcess(¤tPSN);
- panelNotificationUPP = NewDMExtendedNotificationProc(WorldChangedExtendedProc);
- err = DMRegisterExtendedNotifyProc( panelNotificationUPP, // the proc to notify
- (void *) nil, // user data (we have none)
- (unsigned short) nil, // currently unused - set to zero
- ¤tPSN); // our app process serial number
-
- return err;
-
- }
-
- //----------------------------------------------------------------------
- //
- // WorldChangedExtendedProc - Display Manager calls this proc when a depth or
- // mode change is made. Your application should
- // handle window repositioning here.
- //
- //----------------------------------------------------------------------
-
- pascal OSErr WorldChangedExtendedProc(void* userData,short theMessage,void* notifyData)
- {
- OSErr err = noErr;
- // Take a look at Displays.h for the
- // full list of event types.
- if (theMessage == kDMNotifyEvent) // post-notification event
- {
- err = HandleNotification((AppleEvent *)notifyData);
- }
- return noErr;
-
- }
-
- //----------------------------------------------------------------------
- //
- // HandleNotification - handle the AppleEvent returned by the
- // AppleEvent procedure.
- //
- //----------------------------------------------------------------------
-
- OSErr HandleNotification(AppleEvent *event)
- {
- OSErr err = noErr;
- GrafPtr oldPort;
- AEDescList displayList;
- AEDescList aDisplay;
- AERecord oldConfig,newConfig;
- AEKeyword tempWord;
- DisplayIDType displayID;
- unsigned long returnType;
- long count;
- Rect oldRect, newRect;
- Size actualSizeUnused;
-
- GetPort(&oldPort);
-
- // Get a list of the displays from the Display Notice AppleEvent.
- err = AEGetParamDesc(event,kAEDisplayNotice,typeWildCard,&displayList);
- // How many items in the list
- err = AECountItems(&displayList,&count);
-
- while (count > 0) // Loop through the list.
- {
- err = AEGetNthDesc(&displayList, count, typeWildCard, &tempWord,
- &aDisplay);
-
- // Get the Old Rect.
- err = AEGetNthDesc(&aDisplay, 1, typeWildCard, &tempWord,
- &oldConfig);
- err = AEGetKeyPtr(&oldConfig, keyDeviceRect, typeWildCard,
- &returnType, &oldRect, 8, &actualSizeUnused);
-
- // Get the DisplayID so we can get the GDevice later.
- err = AEGetKeyPtr(&oldConfig, keyDisplayID, typeWildCard,
- &returnType, &displayID, 8, &actualSizeUnused);
-
- // Get the New Rect.
- err = AEGetNthDesc(&aDisplay, 2, typeWildCard, &tempWord,
- &newConfig);
- err = AEGetKeyPtr(&newConfig, keyDeviceRect, typeWildCard,
- &returnType, &newRect, 8, &actualSizeUnused);
-
- // If the New and Old rects are not the same then we can assume
- // the GDevice has changed and we need to rearrange the windows.
- if (err == noErr && !EqualRect(&newRect, &oldRect))
- HandleDeviceChange(displayID, &newRect);
-
- count--;
- err = AEDisposeDesc(&aDisplay);
- err = AEDisposeDesc(&oldConfig);
- err = AEDisposeDesc(&newConfig);
-
- }
-
- err = AEDisposeDesc(&displayList);
- SetPort(oldPort);
-
- return err;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // HandleDeviceChange - called when the oldconfig is different from
- // newconfig. Will check all windows on effected
- // device and move if needed.
- //----------------------------------------------------------------------
-
- OSErr HandleDeviceChange(DisplayIDType displayID, Rect *newRect)
- {
- OSErr err;
- GDHandle gd;
- GDHandle onGD;
- WindowRef window;
-
- // Get the GDevice from the DisplayID.
- err = DMGetGDeviceByDisplayID((DisplayIDType) displayID, &gd, false);
-
- if (err == noErr && gd != nil)
- {
- window = LMGetWindowList();
-
- while (nil != window)
- {
- SetPort(window);
- // which device holds the greatest portion of the window
- onGD = GetGreatestDevice(window);
-
- // If the window is not 50% or greater on
- // the desired device then pass it up.
- if (onGD == gd)
- {
- if (OutOfBoundsRect(window->portRect, *newRect))
- {
- MoveInbounds(window, gd, *newRect);
- if (OutOfBoundsRect(window->portRect, *newRect))
- {
- ResizeInbounds(window, gd, *newRect);
-
- // If it is one of our document windows then we need
- // to reset the std state and the scroll bars.
- if (GetIsAppWindow(window))
- AdjustScrollbars(window, true);
- }
- }
- ResetStdState(window);
-
- }
- window = (WindowRef)(((WindowPeek)window)->nextWindow);
- }
- }
-
- return err;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // OutOfBoundsRect - check to see if the window is out of the device
- // rect.
- //
- //----------------------------------------------------------------------
-
- Boolean OutOfBoundsRect(Rect windRect, Rect screenRect)
- {
- Boolean out = false;
-
-
- GlobalToLocal(&TopLeft(screenRect));
- GlobalToLocal(&BotRight(screenRect));
-
- if ((windRect.right > screenRect.right) || (windRect.bottom > screenRect.bottom))
- out = true;
-
- if ((windRect.left < screenRect.left) || (windRect.top < screenRect.top))
- out = true;
-
- return out;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // MoveInbounds - Move window on to desired device
- //
- //
- //----------------------------------------------------------------------
-
- void MoveInbounds(WindowRef window, GDHandle gd, Rect screenRect)
- {
- Rect bounds;
- short hGlobal;
- short vGlobal;
-
- bounds = window->portRect;
-
- LocalToGlobal(&TopLeft(bounds));
- LocalToGlobal(&BotRight(bounds));
-
- hGlobal = bounds.left;
- vGlobal = bounds.top;
-
- // we want to make the left top a priority so adjust it first
- // as to override the bottom, right movements. This is so we
- // can resize the window later. No need to adjust the top
- // because the top coordinates don't change.
-
- if (((bounds.right - bounds.left) > (screenRect.right - screenRect.left)) ||
- ((bounds.bottom - bounds.top) > (screenRect.bottom - screenRect.top)))
- {
-
- // adjust left
- if (bounds.left < screenRect.left)
- hGlobal = screenRect.left + 4;
-
- vGlobal = screenRect.top;
- if (gd == GetMainDevice())
- vGlobal += (GetMBarHeight() + GetWTitleHeight(window));
-
- }
- else
- {
- // adjust left
- if (bounds.left < screenRect.left)
- hGlobal = screenRect.left + 4;
-
- if ((bounds.top - 100 < screenRect.top) && (gd == GetMainDevice()))
- vGlobal = screenRect.top + (GetMBarHeight() + GetWTitleHeight(window));
-
- // adjust right
- if (bounds.right > screenRect.right)
- hGlobal = (screenRect.right - (bounds.right - bounds.left)) - 4;
-
- // adjust bottom
- if (bounds.bottom > screenRect.bottom)
- vGlobal = (screenRect.bottom - (bounds.bottom - bounds.top)) - 4;
- }
-
- MoveWindow(window, hGlobal, vGlobal,false);
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // ResizeInbounds - resize the window to fit in the graphics device
- //
- //
- //----------------------------------------------------------------------
-
- void ResizeInbounds(WindowRef window, GDHandle gd, Rect screenRect)
- {
- Rect windRect;
- short h;
- short v;
-
- windRect = window->portRect;
-
- // make the window bounds the size of the gdRect
- // less the fudge factor.
- h = windRect.right - windRect.left;
- v = windRect.bottom - windRect.top;
-
- if (h > screenRect.right - screenRect.left)
- h = (screenRect.right - screenRect.left) - 8;
-
- if (v > screenRect.bottom - screenRect.top)
- {
- v = (screenRect.bottom - screenRect.top) - 8;
-
- // If we are on the main device then subtract the mBar
- // height. Also subtract the height of the title
- // bar on the window.
-
- if (gd == GetMainDevice())
- v -= (LMGetMBarHeight() + GetWTitleHeight(window));
- }
-
-
- SizeWindow(window, h, v, true);
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // GetGreatestDevice - find thw device that holds the greatest area
- // of the window.
- //
- //----------------------------------------------------------------------
-
- GDHandle GetGreatestDevice(WindowRef window)
- {
- GDHandle gd;
- GDHandle savedGD;
- Rect gdRect;
- Rect foundRect;
- long size;
- long greatest = nil;
-
- gd = DMGetFirstScreenDevice(dmOnlyActiveDisplays);
- savedGD = gd;
-
- // Loop through the device list
- while (gd != nil)
- {
- gdRect = (**gd).gdRect;
-
- GlobalToLocal(&topLeft(gdRect));
- GlobalToLocal(&botRight(gdRect));
-
- if (SectRect(&window->portRect, &gdRect, &foundRect))
- {
- size = ((long)(foundRect.right - foundRect.left) *
- (long)(foundRect.bottom - foundRect.top));
-
- if (size > greatest)
- {
- greatest = size;
- savedGD = gd; // save the greatest device
- }
- }
- gd = DMGetNextScreenDevice(gd, dmOnlyActiveDisplays);
- }
-
- return savedGD;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // ResetStdState - since we are now on a different size screen we need
- // to change the stdState window size so our zooming
- // will work properly.
- //----------------------------------------------------------------------
-
- void ResetStdState(WindowRef window)
- {
- Rect screenRect;
-
- screenRect = window->portRect;
-
- LocalToGlobal(&TopLeft(screenRect));
- LocalToGlobal(&BotRight(screenRect));
-
- SetWindowStandardState(window, &screenRect);
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // GetWTitleHeight - return the height of the titlebar for a given
- // window. If the window is nil a zero height will
- // be returned.
- //----------------------------------------------------------------------
-
- short GetWTitleHeight(WindowRef window)
- {
- short tHeight = 0;
-
- if (nil != window)
- tHeight = (**((WindowPeek)window)->contRgn).rgnBBox.top -
- (**((WindowPeek)window)->strucRgn).rgnBBox.top;
-
- return tHeight;
-
- }
-
-
-